package com.ruoyi.client;

import com.alibaba.fastjson.JSONException;
import com.alibaba.fastjson.JSONObject;
import com.ruoyi.pay.utils.APIException;
import com.ruoyi.pay.utils.InvalidRequestException;
import com.ruoyi.client.exception.JeepayException;
import com.ruoyi.client.request.JeepayRequest;
import com.ruoyi.client.request.RequestOptions;
import com.ruoyi.client.response.PayResponse;
import com.ruoyi.client.util.JSONWriter;
import com.ruoyi.client.vo.*;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.web.bind.annotation.RequestMethod;

import java.util.HashMap;
import java.util.Map;

/**
 * <简述>
 * <详细描述>
 *
 * @author syf
 * @date 2025年03月12日 12:20
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
public class PayClientPls {
   private String signType = Pay.DEFAULT_SIGN_TYPE;
    private String apiKey = Pay.apiKey;
    private String apiBase = Pay.getApiBase();

    private String appId;


    private static HttpClient httpClient = new HttpURLConnectionClient();


    private static Map<String, PayClientPls> clientMap = new HashMap<String, PayClientPls>();


    public static synchronized PayClientPls getInstance(String appId, String apiKey, String apiBase) {
        PayClientPls client = clientMap.get(appId);
        if (client != null) {
            client.setApiKey(apiKey);
            client.setApiBase(apiBase);
            return client;
        }
        client = new PayClientPls();
        clientMap.put(appId, client);
        client.appId = appId;
        client.apiKey = apiKey;
        client.apiBase = apiBase;
        return client;
    }


    public PayClientPls(String apiBase, String signType, String apiKey) {
        this.apiBase = apiBase;
        this.signType = signType;
        this.apiKey = apiKey;
    }

    public PayClientPls(String apiBase, String apiKey) {
        this.apiBase = apiBase;
        this.apiKey = apiKey;
    }


    /**
     * <简述>请求下单接口，返回调用支付宝信息
     * <详细描述>
     * @author syf
     * @date 2025/3/26 15:30
     * @return T
     */
    public <T extends PayResponse> T execute(JeepayRequest<T> request) throws JeepayException {

        // 支持用户自己设置RequestOptions
        if(request.getRequestOptions() == null) {
            RequestOptions options = RequestOptions.builder()
                .setVersion(request.getApiVersion())
                .setUri(request.getApiUri())
                .setApiKey(this.apiKey)
                .build();
            request.setRequestOptions(options);
        }

        return sendePost(request, RequestMethod.POST, this.apiBase);
    }


    /**
     * <简述>请求下单接口，返回调用支付宝信息
     * <详细描述>
     * @author syf
     * @date 2025/3/26 15:30
     * @param request
     * @param method
     * @param url
     * @return T
     */
    public <T extends PayResponse> T sendePost(
        JeepayRequest<T> request,
        RequestMethod method,
        String url) throws JeepayException {
        //入参
        String jsonParam = new JSONWriter().write(request.getBizModel(), true);
        JSONObject params = JSONObject.parseObject(jsonParam);

         RequestOptions requestOptions = request.getRequestOptions();
        //生成请求 加签
        APIPayRequest apiPayRequest = new APIPayRequest(method, url, params, requestOptions);

        APIPayResponse response = httpClient.requestWithRetries(apiPayRequest);
        int responseCode = response.getResponseCode();
        if (responseCode != 200) {
            handleAPIError(response);
        }

        T resource = null;

        String responseBody = response.getResponseBody();
        try {
            resource = JSONObject.parseObject(responseBody, request.getResponseClass());
        } catch (JSONException e) {
            raiseMalformedJsonError(responseBody, responseCode);
        }
        return resource;
    }


    private static void handleAPIError(APIPayResponse response)
        throws JeepayException {

        String rBody = response.getResponseBody();
        int rCode = response.getResponseCode();
        JSONObject jsonObject = new JSONObject();
        try {
            jsonObject = JSONObject.parseObject(rBody);

        } catch (JSONException e) {
            raiseMalformedJsonError(rBody, rCode);
        }

        if(rCode == 404) {
            throw new InvalidRequestException(jsonObject.getString("status") + ", "
                + jsonObject.getString("error") + ", "
                + jsonObject.getString("path")
                , rCode, null);
        }

    }

    private static void raiseMalformedJsonError(
        String responseBody, int responseCode) throws APIException {
        throw new APIException(
            String.format(
                "Invalid response object from API: %s. (HTTP response code was %d)",
                responseBody, responseCode),
            null,
            null,
            responseCode,
            null);
    }



    public <T extends PayResponse> T executeByRSA2(JeepayRequest<T> request) throws JeepayException {

        // 支持用户自己设置RequestOptions
        if (request.getRequestOptions() == null) {
            RequestOptions options = RequestOptions.builder()
                .setVersion(request.getApiVersion())
                .setUri(request.getApiUri())
                .setAppId(this.appId)
                .setApiKey(this.apiKey)
                .setSignType(Pay.SIGN_TYPE_RSA2)
                .build();
            request.setRequestOptions(options);
        }

        return sendePost(request, RequestMethod.POST, this.apiBase);
    }
}
